Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / tests / backend / test_crash_recovery.py

Displaying Raw • Download


tests/backend/test_crash_recovery.py dev (af76f09d) Text, 21.31 KB

T8b949e# SPDX-License-Identifier: 0BSD

Tff7b72import T7ee787io
Tff7b72import T7ee787os
Tff7b72import T7ee787shutil
Tff7b72import T7ee787sqlite3
Tff7b72import T7ee787sys
Tff7b72import T7ee787tempfile
Tff7b72import T7ee787unittest
Tff7b72from T7ee787unittestT7ee787.T7ee787mock Tff7b72import Te6edf3MagicMockTb4b4b4, Te6edf3patch

Tff7b72import T7ee787RNS

Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787recoveryT7ee787.T7ee787crash_recovery Tff7b72import Te6edf3CrashRecovery


Tff7b72class T56d364TestCrashRecoveryTb4b4b4(Te6edf3unittestTff7b72.Td2a8ffTestCaseTb4b4b4)Tb4b4b4:
Tff7b72def Td2a8ffsetUpTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8fftest_dir Tff7b72= Te6edf3tempfileTff7b72.Td2a8ffmkdtempTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffstorage_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8fftest_dirTb4b4b4, Ta5d6ff"Ta5d6ffstorageTa5d6ff"Tb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffdb_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4, Ta5d6ff"Ta5d6fftest.dbTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffpublic_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8fftest_dirTb4b4b4, Ta5d6ff"Ta5d6ffpublicTa5d6ff"Tb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpublic_dirTb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpublic_dirTb4b4b4, Ta5d6ff"Ta5d6ffindex.htmlTa5d6ff"Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Ta5d6ff"Ta5d6fftestTa5d6ff"Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffrecovery Tff7b72= Te6edf3CrashRecoveryTb4b4b4(
Te6edf3storage_dirTff7b72=Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4,
Te6edf3database_pathTff7b72=Tff7b72selfTff7b72.Td2a8ffdb_pathTb4b4b4,
Te6edf3public_dirTff7b72=Tff7b72selfTff7b72.Td2a8ffpublic_dirTb4b4b4,
Tb4b4b4)

Tff7b72def Td2a8fftearDownTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3shutilTff7b72.Td2a8ffrmtreeTb4b4b4(Tff7b72selfTff7b72.Td2a8fftest_dirTb4b4b4)

Tff7b72def Td2a8fftest_diagnosis_normalTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e# Create a valid DB
Te6edf3conn Tff7b72= Te6edf3sqlite3Tff7b72.Td2a8ffconnectTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdb_pathTb4b4b4)
Te6edf3connTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"Ta5d6ffCREATE TABLE test (id INTEGER PRIMARY KEY)Ta5d6ff"Tb4b4b4)
Te6edf3connTff7b72.Td2a8ffcloseTb4b4b4(Tb4b4b4)

Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffrun_diagnosisTb4b4b4(Te6edf3fileTff7b72=Te6edf3outputTb4b4b4)
Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffOS:Ta5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffPython:Ta5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffStorage Path:Ta5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffIntegrity: OKTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffFrontend Status: Assets verifiedTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)

Tff7b72def Td2a8fftest_diagnosis_missing_storageTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3shutilTff7b72.Td2a8ffrmtreeTb4b4b4(Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4)
Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffrun_diagnosisTb4b4b4(Te6edf3fileTff7b72=Te6edf3outputTb4b4b4)
Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ff[ERROR] Storage path does not existTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)

Tff7b72def Td2a8fftest_diagnosis_corrupt_dbTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdb_pathTb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Ta5d6ff"Ta5d6ffnot a sqlite databaseTa5d6ff"Tb4b4b4)

Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffrun_diagnosisTb4b4b4(Te6edf3fileTff7b72=Te6edf3outputTb4b4b4)
Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ff[ERROR] Database is unreadableTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)

Tff7b72def Td2a8fftest_diagnosis_missing_frontendTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3shutilTff7b72.Td2a8ffrmtreeTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpublic_dirTb4b4b4)
Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffrun_diagnosisTb4b4b4(Te6edf3fileTff7b72=Te6edf3outputTb4b4b4)
Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ff[ERROR] Frontend directory is missingTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)

Tff7b72def Td2a8fftest_diagnosis_rns_missing_configTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3rns_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8fftest_dirTb4b4b4, Ta5d6ff"Ta5d6ffrns_missingTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffupdate_pathsTb4b4b4(Te6edf3reticulum_config_dirTff7b72=Te6edf3rns_dirTb4b4b4)
Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffrun_diagnosisTb4b4b4(Te6edf3fileTff7b72=Te6edf3outputTb4b4b4)
Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ff[ERROR] Reticulum config directory does not existTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)

Tff7b72def Td2a8fftest_reticulum_diagnosis_skips_false_missing_when_path_unsetTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3patchTff7b72.Td2a8ffobjectTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffReticulumTb4b4b4, Ta5d6ff"Ta5d6ffconfigpathTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffupdate_pathsTb4b4b4(Te6edf3reticulum_config_dirTff7b72=Tff7b72NoneTb4b4b4)
Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffrun_reticulum_diagnosisTb4b4b4(Te6edf3fileTff7b72=Te6edf3outputTb4b4b4)
Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ff(not resolved yet)Ta5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertNotInTb4b4b4(
Ta5d6ff"Ta5d6ff[ERROR] Reticulum config directory does not existTa5d6ff"Tb4b4b4,
Te6edf3reportTb4b4b4,
Tb4b4b4)

Tff7b72def Td2a8fftest_diagnosis_rns_log_extractionTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3rns_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8fftest_dirTb4b4b4, Ta5d6ff"Ta5d6ffrns_logTa5d6ff"Tb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3rns_dirTb4b4b4)
Te6edf3log_file Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rns_dirTb4b4b4, Ta5d6ff"Ta5d6fflogfileTa5d6ff"Tb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3log_fileTb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Ta5d6ff"Ta5d6ffLine 1Tffea00\nTa5d6ffLine 2Tffea00\nTa5d6ffERROR: Something went wrongTffea00\nTa5d6ff"Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffupdate_pathsTb4b4b4(Te6edf3reticulum_config_dirTff7b72=Te6edf3rns_dirTb4b4b4)
Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffrun_diagnosisTb4b4b4(Te6edf3fileTff7b72=Te6edf3outputTb4b4b4)
Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffRecent Log EntriesTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ff> [ALERT] ERROR: Something went wrongTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)

Tff7b72def Td2a8fftest_env_disableTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffenvironTb4b4b4[Ta5d6ff"Ta5d6ffMESHCHAT_NO_CRASH_RECOVERYTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6ff1Ta5d6ff"
Te6edf3recovery Tff7b72= Te6edf3CrashRecoveryTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertFalseTb4b4b4(Te6edf3recoveryTff7b72.Td2a8ffenabledTb4b4b4)
Tff7b72del Te6edf3osTff7b72.Td2a8ffenvironTb4b4b4[Ta5d6ff"Ta5d6ffMESHCHAT_NO_CRASH_RECOVERYTa5d6ff"Tb4b4b4]

Tff7b72def Td2a8fftest_handle_exception_formatTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e# We don't want to actually sys.exit(1) in tests, so we mock it
Te6edf3original_exit Tff7b72= Te6edf3sysTff7b72.Td2a8ffexit
Te6edf3sysTff7b72.Td2a8ffexit Tff7b72= Tff7b72lambda Te6edf3xTb4b4b4: Tff7b72None

Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
T8b949e# Redirect stderr to our buffer
Te6edf3original_stderr Tff7b72= Te6edf3sysTff7b72.Td2a8ffstderr
Te6edf3sysTff7b72.Td2a8ffstderr Tff7b72= Te6edf3output

Tff7b72tryTb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffSimulated error for testingTa5d6ff"Tb4b4b4)
Tff7b72except Tf85149ValueErrorTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffhandle_exceptionTb4b4b4(Tff7b72*Te6edf3sysTff7b72.Td2a8ffexc_infoTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72finallyTb4b4b4:
Te6edf3sysTff7b72.Td2a8ffstderr Tff7b72= Te6edf3original_stderr
Te6edf3sysTff7b72.Td2a8ffexit Tff7b72= Te6edf3original_exit

Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ff!!! APPLICATION CRASH DETECTED !!!Ta5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffType: ValueErrorTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffMessage: Simulated error for testingTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffRoot Cause Analysis:Ta5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffRecovery Suggestions:Ta5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)

Tff7b72def Td2a8fftest_heuristic_analysis_sqliteTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3exc_type Tff7b72= Tffa657typeTb4b4b4(Ta5d6ff"Ta5d6ffOperationalErrorTa5d6ff"Tb4b4b4, Tb4b4b4(Tf85149ExceptionTb4b4b4,Tb4b4b4)Tb4b4b4, Tb4b4b4{Tb4b4b4}Tb4b4b4)
Te6edf3exc_typeTff7b72.Td2a8ff__name__ Tff7b72= Ta5d6ff"Ta5d6ffsqlite3.OperationalErrorTa5d6ff"
Te6edf3exc_value Tff7b72= Tf85149ExceptionTb4b4b4(Ta5d6ff"Ta5d6ffno such table: configTa5d6ff"Tb4b4b4)
Te6edf3diagnosis Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6ffdb_typeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmemoryTa5d6ff"Tb4b4b4}

Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Te6edf3diagnosisTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertTrueTb4b4b4(Tffa657lenTb4b4b4(Te6edf3causesTb4b4b4) Tff7b72> T79c0ff0Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6ffIn-Memory Database Sync FailureTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_heuristic_analysis_asyncioTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3exc_type Tff7b72= Tf85149RuntimeError
Te6edf3exc_value Tff7b72= Tf85149RuntimeErrorTb4b4b4(Ta5d6ff"Ta5d6ffno current event loopTa5d6ff"Tb4b4b4)
Te6edf3diagnosis Tff7b72= Tb4b4b4{Tb4b4b4}

Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Te6edf3diagnosisTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertTrueTb4b4b4(Tffa657lenTb4b4b4(Te6edf3causesTb4b4b4) Tff7b72> T79c0ff0Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffAsynchronous InitializationTa5d6ff"Tb4b4b4, Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4]Tb4b4b4)

Tff7b72def Td2a8fftest_heuristic_analysis_oom_priorityTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Verify that low memory increases OOM probability even with other errors."""
Te6edf3exc_type Tff7b72= Te6edf3sqlite3Tff7b72.Td2a8ffOperationalError
Te6edf3exc_value Tff7b72= Te6edf3sqlite3Tff7b72.Td2a8ffOperationalErrorTb4b4b4(Ta5d6ff"Ta5d6ffdatabase is lockedTa5d6ff"Tb4b4b4)
T8b949e# Scenario: Low memory + DB error
Te6edf3diagnosis Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6fflow_memoryTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4, Ta5d6ff"Ta5d6ffavailable_mem_mbTa5d6ff"Tb4b4b4: T79c0ff10Tb4b4b4}

Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Te6edf3diagnosisTb4b4b4)
T8b949e# OOM should be prioritized or at least highly probable (85% in code)
Te6edf3oom_cause Tff7b72= Tffa657nextTb4b4b4(Tb4b4b4(Te6edf3c Tff7b72for Te6edf3c Tff7b72in Te6edf3causes Tff7b72if Ta5d6ff"Ta5d6ffOOMTa5d6ff" Tff7b72in Te6edf3cTb4b4b4[Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4]Tb4b4b4)Tb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsNotNoneTb4b4b4(Te6edf3oom_causeTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3oom_causeTb4b4b4[Ta5d6ff"Ta5d6ffprobabilityTa5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff85Tb4b4b4)

Tff7b72def Td2a8fftest_heuristic_analysis_memoryerrorTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(
Tf85149MemoryErrorTb4b4b4,
Tf85149MemoryErrorTb4b4b4(Ta5d6ff"Ta5d6ffunable to allocate arrayTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4{Ta5d6ff"Ta5d6fflow_memoryTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4, Ta5d6ff"Ta5d6ffavailable_mem_mbTa5d6ff"Tb4b4b4: T79c0ff1024Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3oom_cause Tff7b72= Tffa657nextTb4b4b4(Tb4b4b4(Te6edf3c Tff7b72for Te6edf3c Tff7b72in Te6edf3causes Tff7b72if Ta5d6ff"Ta5d6ffOOMTa5d6ff" Tff7b72in Te6edf3cTb4b4b4[Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4]Tb4b4b4)Tb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsNotNoneTb4b4b4(Te6edf3oom_causeTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3oom_causeTb4b4b4[Ta5d6ff"Ta5d6ffprobabilityTa5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff95Tb4b4b4)

Tff7b72def Td2a8fftest_heuristic_analysis_rns_missingTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Verify high confidence for missing RNS config."""
Te6edf3exc_type Tff7b72= Tf85149RuntimeError
Te6edf3exc_value Tff7b72= Tf85149RuntimeErrorTb4b4b4(Ta5d6ff"Ta5d6ffReticulum could not startTa5d6ff"Tb4b4b4)
Te6edf3diagnosis Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6ffconfig_missingTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4}

Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Te6edf3diagnosisTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6ffMissing Reticulum ConfigurationTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffprobabilityTa5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff99Tb4b4b4)

Tff7b72def Td2a8fftest_heuristic_analysis_permission_denied_priorityTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3exc_type Tff7b72= Tf85149PermissionError
Te6edf3exc_value Tff7b72= Tf85149PermissionErrorTb4b4b4(T79c0ff13Tb4b4b4, Ta5d6ff"Ta5d6ffPermission deniedTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff/config/.meshchatTa5d6ff"Tb4b4b4)
Te6edf3diagnosis Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6ffconfig_missingTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4, Ta5d6ff"Ta5d6ffpermission_deniedTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4}

Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Te6edf3diagnosisTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6ffFilesystem Permission DeniedTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffprobabilityTa5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff99Tb4b4b4)

Tff7b72def Td2a8fftest_run_diagnosis_permission_crash_contextTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
Te6edf3exc Tff7b72= Tf85149PermissionErrorTb4b4b4(T79c0ff13Tb4b4b4, Ta5d6ff"Ta5d6ffPermission deniedTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff/data/meshchatTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffrun_diagnosisTb4b4b4(Te6edf3fileTff7b72=Te6edf3outputTb4b4b4, Te6edf3crash_exceptionTff7b72=Te6edf3excTb4b4b4)
Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffFilesystem permission failureTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ff/data/meshchatTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)

Tff7b72def Td2a8fftest_entropy_calculation_levelsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Test how entropy reflects system disorder."""
T8b949e# Baseline stable state
Te6edf3stable_diag Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6fflow_memoryTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4, Ta5d6ff"Ta5d6ffconfig_missingTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4}
Te6edf3stable_entropyTb4b4b4, Te6edf3_ Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_calculate_system_entropyTb4b4b4(Te6edf3stable_diagTb4b4b4)

T8b949e# Unstable state (one critical issue)
Te6edf3unstable_diag Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6fflow_memoryTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4, Ta5d6ff"Ta5d6ffconfig_missingTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4}
Te6edf3unstable_entropyTb4b4b4, Te6edf3_ Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_calculate_system_entropyTb4b4b4(Te6edf3unstable_diagTb4b4b4)

T8b949e# Very unstable state (multiple critical issues)
Te6edf3very_unstable_diag Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6fflow_memoryTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4, Ta5d6ff"Ta5d6ffconfig_missingTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4}
Te6edf3very_unstable_entropyTb4b4b4, Te6edf3_ Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_calculate_system_entropyTb4b4b4(
Te6edf3very_unstable_diagTb4b4b4,
Tb4b4b4)

T8b949e# Entropy should increase with more issues
Tff7b72selfTff7b72.Td2a8ffassertGreaterTb4b4b4(Te6edf3unstable_entropyTb4b4b4, Te6edf3stable_entropyTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertGreaterTb4b4b4(Te6edf3very_unstable_entropyTb4b4b4, Te6edf3unstable_entropyTb4b4b4)

T8b949e# Max entropy for 2 binary states is at p=0.5, but here we sum
T8b949e# p_unstable = 0.1 + 0.4 + 0.4 = 0.9.
T8b949e# p=0.9 has lower entropy than p=0.5, but higher than p=0.1.
T8b949e# p_stable=0.9 (stable) vs p_stable=0.5 (medium) vs p_stable=0.1 (unstable)
T8b949e# H(0.1) = 0.469, H(0.5) = 1.0, H(0.9) = 0.469
T8b949e# The current implementation:
T8b949e# stable: p_unstable=0.1 -> H=0.469
T8b949e# unstable: p_unstable=0.5 -> H=1.0
T8b949e# very unstable: p_unstable=0.9 -> H=0.469 (wait, mathematically yes, but logically?)
T8b949e# Actually for a "disorder" metric, we might want it to peak when things are most uncertain.
T8b949e# But in our context, we are showing entropy of the "State Predictability".

Tff7b72def Td2a8fftest_heuristic_analysis_lxmf_storageTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Test LXMF storage failure detection."""
Te6edf3exc_type Tff7b72= Tf85149RuntimeError
Te6edf3exc_value Tff7b72= Tf85149RuntimeErrorTb4b4b4(Ta5d6ff"Ta5d6ffLXMF could not open storage directoryTa5d6ff"Tb4b4b4)
Te6edf3diagnosis Tff7b72= Tb4b4b4{Tb4b4b4}

Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Te6edf3diagnosisTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6ffLXMF Router Storage FailureTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffprobabilityTa5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff90Tb4b4b4)

Tff7b72def Td2a8fftest_heuristic_analysis_rns_identityTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Test Reticulum identity failure detection."""
Te6edf3exc_type Tff7b72= Tf85149Exception
Te6edf3exc_value Tff7b72= Tf85149ExceptionTb4b4b4(Ta5d6ff"Ta5d6ffReticulum Identity load failed: corrupt private keyTa5d6ff"Tb4b4b4)
Te6edf3diagnosis Tff7b72= Tb4b4b4{Tb4b4b4}

Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Te6edf3diagnosisTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6ffReticulum Identity Load FailureTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffprobabilityTa5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff95Tb4b4b4)

Tff7b72def Td2a8fftest_heuristic_analysis_interface_offlineTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Test interface offline detection."""
Te6edf3exc_type Tff7b72= Tf85149RuntimeError
Te6edf3exc_value Tff7b72= Tf85149RuntimeErrorTb4b4b4(Ta5d6ff"Ta5d6ffReticulum startup failedTa5d6ff"Tb4b4b4)
Te6edf3diagnosis Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6ffactive_interfacesTa5d6ff"Tb4b4b4: T79c0ff0Tb4b4b4}

T8b949e# We need to trigger the rns_in_msg symptom as well
Te6edf3exc_value Tff7b72= Tf85149RuntimeErrorTb4b4b4(Ta5d6ff"Ta5d6ffReticulum failed, no path availableTa5d6ff"Tb4b4b4)
Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Te6edf3diagnosisTb4b4b4)

Te6edf3offline_cause Tff7b72= Tffa657nextTb4b4b4(
Tb4b4b4(Te6edf3c Tff7b72for Te6edf3c Tff7b72in Te6edf3causes Tff7b72if Ta5d6ff"Ta5d6ffInterfaceTa5d6ff" Tff7b72in Te6edf3cTb4b4b4[Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4]Tb4b4b4)Tb4b4b4,
Tff7b72NoneTb4b4b4,
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsNotNoneTb4b4b4(Te6edf3offline_causeTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3offline_causeTb4b4b4[Ta5d6ff"Ta5d6ffprobabilityTa5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff85Tb4b4b4)

Tff7b72def Td2a8fftest_advanced_math_outputTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e# We don't want to actually sys.exit(1) in tests, so we mock it
Te6edf3original_exit Tff7b72= Te6edf3sysTff7b72.Td2a8ffexit
Te6edf3sysTff7b72.Td2a8ffexit Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)

Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
T8b949e# Redirect stderr to our buffer
Te6edf3original_stderr Tff7b72= Te6edf3sysTff7b72.Td2a8ffstderr
Te6edf3sysTff7b72.Td2a8ffstderr Tff7b72= Te6edf3output

Tff7b72tryTb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72raise Tf85149RuntimeErrorTb4b4b4(Ta5d6ff"Ta5d6ffno current event loopTa5d6ff"Tb4b4b4)
Tff7b72except Tf85149RuntimeErrorTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffhandle_exceptionTb4b4b4(Tff7b72*Te6edf3sysTff7b72.Td2a8ffexc_infoTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72finallyTb4b4b4:
Te6edf3sysTff7b72.Td2a8ffstderr Tff7b72= Te6edf3original_stderr
Te6edf3sysTff7b72.Td2a8ffexit Tff7b72= Te6edf3original_exit

Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ff[System Entropy:Ta5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ff[KL-Divergence:Ta5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)

Tff7b72def Td2a8fftest_heuristic_analysis_unsupported_pythonTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Test detection of unsupported Python versions."""
T8b949e# We need to simulate the sys.version_info check
Tff7b72with Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffsys.version_infoTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3mock_versionTb4b4b4:
Te6edf3mock_versionTff7b72.Td2a8ffmajor Tff7b72= T79c0ff3
Te6edf3mock_versionTff7b72.Td2a8ffminor Tff7b72= T79c0ff9

Te6edf3exc_type Tff7b72= Tf85149AttributeError
Te6edf3exc_value Tff7b72= Tf85149AttributeErrorTb4b4b4(Ta5d6ff"Ta5d6ff'Ta5d6ffNoneTypeTa5d6ff'Ta5d6ff object has no attribute Ta5d6ff'Ta5d6ffxTa5d6ff'Ta5d6ff"Tb4b4b4)
Te6edf3diagnosis Tff7b72= Tb4b4b4{Tb4b4b4}

Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Te6edf3diagnosisTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6ffUnsupported Python EnvironmentTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffprobabilityTa5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff99Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(
Ta5d6ff"Ta5d6ffmissing standard library featuresTa5d6ff"Tb4b4b4,
Te6edf3causesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffreasoningTa5d6ff"Tb4b4b4]Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Tff7b72def Td2a8fftest_heuristic_analysis_legacy_kernelTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Test detection of legacy system/kernel limitations."""
Tff7b72with Tb4b4b4(
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffplatform.systemTa5d6ff"Tb4b4b4, Te6edf3return_valueTff7b72=Ta5d6ff"Ta5d6ffLinuxTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffplatform.releaseTa5d6ff"Tb4b4b4, Te6edf3return_valueTff7b72=Ta5d6ff"Ta5d6ff3.10.0-1160.el7.x86_64Ta5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3exc_type Tff7b72= Tf85149RuntimeError
Te6edf3exc_value Tff7b72= Tf85149RuntimeErrorTb4b4b4(Ta5d6ff"Ta5d6ffkernel feature not availableTa5d6ff"Tb4b4b4)
Te6edf3diagnosis Tff7b72= Tb4b4b4{Tb4b4b4}

Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Te6edf3diagnosisTb4b4b4)
Te6edf3legacy_cause Tff7b72= Tffa657nextTb4b4b4(
Tb4b4b4(Te6edf3c Tff7b72for Te6edf3c Tff7b72in Te6edf3causes Tff7b72if Ta5d6ff"Ta5d6ffLegacy SystemTa5d6ff" Tff7b72in Te6edf3cTb4b4b4[Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4]Tb4b4b4)Tb4b4b4,
Tff7b72NoneTb4b4b4,
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsNotNoneTb4b4b4(Te6edf3legacy_causeTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertGreaterEqualTb4b4b4(Te6edf3legacy_causeTb4b4b4[Ta5d6ff"Ta5d6ffprobabilityTa5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff80Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffKernel detected: 3.10Ta5d6ff"Tb4b4b4, Te6edf3legacy_causeTb4b4b4[Ta5d6ff"Ta5d6ffreasoningTa5d6ff"Tb4b4b4]Tb4b4b4)

T8b949e# ==================================================================
T8b949e# install() / disable()
T8b949e# ==================================================================

Tff7b72def Td2a8fftest_install_sets_excepthookTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""install() should set sys.excepthook to handle_exception."""
Te6edf3original Tff7b72= Te6edf3sysTff7b72.Td2a8ffexcepthook
Tff7b72tryTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffinstallTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3sysTff7b72.Td2a8ffexcepthookTb4b4b4, Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffhandle_exceptionTb4b4b4)
Tff7b72finallyTb4b4b4:
Te6edf3sysTff7b72.Td2a8ffexcepthook Tff7b72= Te6edf3original

Tff7b72def Td2a8fftest_disable_prevents_installTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""After disable(), install() should not set the hook."""
Te6edf3original Tff7b72= Te6edf3sysTff7b72.Td2a8ffexcepthook
Tff7b72tryTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffdisableTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffinstallTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertNotEqualTb4b4b4(Te6edf3sysTff7b72.Td2a8ffexcepthookTb4b4b4, Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffhandle_exceptionTb4b4b4)
Tff7b72finallyTb4b4b4:
Te6edf3sysTff7b72.Td2a8ffexcepthook Tff7b72= Te6edf3original

T8b949e# ==================================================================
T8b949e# _calculate_system_entropy edge cases
T8b949e# ==================================================================

Tff7b72def Td2a8fftest_entropy_empty_diagnosisTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Empty diagnosis should return baseline entropy (all ideal)."""
Te6edf3entropyTb4b4b4, Te6edf3divergence Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_calculate_system_entropyTb4b4b4(Tb4b4b4{Tb4b4b4}Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertGreaterTb4b4b4(Te6edf3entropyTb4b4b4, T79c0ff0Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertAlmostEqualTb4b4b4(Te6edf3divergenceTb4b4b4, T79c0ff0.0Tb4b4b4, Te6edf3placesTff7b72=T79c0ff5Tb4b4b4)

Tff7b72def Td2a8fftest_entropy_all_criticalTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""All dimensions critical should maximize entropy and divergence."""
Te6edf3diag Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6fflow_memoryTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Ta5d6ff"Ta5d6ffconfig_missingTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Ta5d6ff"Ta5d6ffdb_typeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmemoryTa5d6ff"Tb4b4b4,
Tb4b4b4}
Te6edf3entropyTb4b4b4, Te6edf3divergence Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_calculate_system_entropyTb4b4b4(Te6edf3diagTb4b4b4)
Te6edf3base_entropyTb4b4b4, Te6edf3base_div Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_calculate_system_entropyTb4b4b4(Tb4b4b4{Tb4b4b4}Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertGreaterTb4b4b4(Te6edf3entropyTb4b4b4, Te6edf3base_entropyTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertGreaterTb4b4b4(Te6edf3divergenceTb4b4b4, Te6edf3base_divTb4b4b4)

Tff7b72def Td2a8fftest_entropy_invalid_mem_valueTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Non-numeric available_mem_mb should not crash."""
Te6edf3diag Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6ffavailable_mem_mbTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffnot_a_numberTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fflow_memoryTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4}
Te6edf3entropyTb4b4b4, Te6edf3divergence Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_calculate_system_entropyTb4b4b4(Te6edf3diagTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsInstanceTb4b4b4(Te6edf3entropyTb4b4b4, Tffa657floatTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsInstanceTb4b4b4(Te6edf3divergenceTb4b4b4, Tffa657floatTb4b4b4)

Tff7b72def Td2a8fftest_entropy_none_mem_valueTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""None available_mem_mb should not crash."""
Te6edf3diag Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6ffavailable_mem_mbTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4}
Te6edf3entropyTb4b4b4, Te6edf3divergence Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_calculate_system_entropyTb4b4b4(Te6edf3diagTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsInstanceTb4b4b4(Te6edf3entropyTb4b4b4, Tffa657floatTb4b4b4)

Tff7b72def Td2a8fftest_divergence_nonnegativeTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""KL divergence must always be non-negative."""
Te6edf3test_cases Tff7b72= Tb4b4b4[
Tb4b4b4{Tb4b4b4}Tb4b4b4,
Tb4b4b4{Ta5d6ff"Ta5d6fflow_memoryTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4}Tb4b4b4,
Tb4b4b4{Ta5d6ff"Ta5d6ffconfig_missingTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4}Tb4b4b4,
Tb4b4b4{Ta5d6ff"Ta5d6ffdb_typeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmemoryTa5d6ff"Tb4b4b4}Tb4b4b4,
Tb4b4b4{Ta5d6ff"Ta5d6fflow_memoryTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4, Ta5d6ff"Ta5d6ffconfig_missingTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4, Ta5d6ff"Ta5d6ffdb_typeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmemoryTa5d6ff"Tb4b4b4}Tb4b4b4,
Tb4b4b4]
Tff7b72for Te6edf3diag Tff7b72in Te6edf3test_casesTb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3div Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_calculate_system_entropyTb4b4b4(Te6edf3diagTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertGreaterEqualTb4b4b4(Te6edf3divTb4b4b4, T79c0ff0.0Tb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffNegative divergence for Tffd700{Te6edf3diagTffd700}Ta5d6ff"Tb4b4b4)

T8b949e# ==================================================================
T8b949e# legacy_kernel regex safety
T8b949e# ==================================================================

Tff7b72def Td2a8fftest_legacy_kernel_non_linuxTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Non-Linux platforms should not crash on legacy_kernel check."""
Tff7b72with Tb4b4b4(
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffplatform.systemTa5d6ff"Tb4b4b4, Te6edf3return_valueTff7b72=Ta5d6ff"Ta5d6ffWindowsTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffplatform.releaseTa5d6ff"Tb4b4b4, Te6edf3return_valueTff7b72=Ta5d6ff"Ta5d6ff10Ta5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3exc_type Tff7b72= Tf85149RuntimeError
Te6edf3exc_value Tff7b72= Tf85149RuntimeErrorTb4b4b4(Ta5d6ff"Ta5d6fftestTa5d6ff"Tb4b4b4)
Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Tb4b4b4{Tb4b4b4}Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsInstanceTb4b4b4(Te6edf3causesTb4b4b4, Tffa657listTb4b4b4)

Tff7b72def Td2a8fftest_legacy_kernel_unusual_releaseTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Unusual release strings should not crash."""
Tff7b72with Tb4b4b4(
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffplatform.systemTa5d6ff"Tb4b4b4, Te6edf3return_valueTff7b72=Ta5d6ff"Ta5d6ffLinuxTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffplatform.releaseTa5d6ff"Tb4b4b4, Te6edf3return_valueTff7b72=Ta5d6ff"Ta5d6ffunknownTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3exc_type Tff7b72= Tf85149RuntimeError
Te6edf3exc_value Tff7b72= Tf85149RuntimeErrorTb4b4b4(Ta5d6ff"Ta5d6fftestTa5d6ff"Tb4b4b4)
Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Tb4b4b4{Tb4b4b4}Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsInstanceTb4b4b4(Te6edf3causesTb4b4b4, Tffa657listTb4b4b4)

Tff7b72def Td2a8fftest_legacy_kernel_empty_releaseTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Empty release string should not crash."""
Tff7b72with Tb4b4b4(
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffplatform.systemTa5d6ff"Tb4b4b4, Te6edf3return_valueTff7b72=Ta5d6ff"Ta5d6ffLinuxTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffplatform.releaseTa5d6ff"Tb4b4b4, Te6edf3return_valueTff7b72=Ta5d6ff"Ta5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3exc_type Tff7b72= Tf85149RuntimeError
Te6edf3exc_value Tff7b72= Tf85149RuntimeErrorTb4b4b4(Ta5d6ff"Ta5d6fftestTa5d6ff"Tb4b4b4)
Te6edf3causes Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ff_analyze_causeTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Tb4b4b4{Tb4b4b4}Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsInstanceTb4b4b4(Te6edf3causesTb4b4b4, Tffa657listTb4b4b4)

T8b949e# ==================================================================
T8b949e# run_reticulum_diagnosis isolation
T8b949e# ==================================================================

Tff7b72def Td2a8fftest_reticulum_diagnosis_invalid_config_contentTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Invalid config file content should be flagged."""
Te6edf3rns_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8fftest_dirTb4b4b4, Ta5d6ff"Ta5d6ffrns_invalidTa5d6ff"Tb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3rns_dirTb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rns_dirTb4b4b4, Ta5d6ff"Ta5d6ffconfigTa5d6ff"Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Ta5d6ff"Ta5d6ffthis is not a valid reticulum configTa5d6ff"Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffupdate_pathsTb4b4b4(Te6edf3reticulum_config_dirTff7b72=Te6edf3rns_dirTb4b4b4)
Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
Te6edf3results Tff7b72= Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffrun_reticulum_diagnosisTb4b4b4(Te6edf3fileTff7b72=Te6edf3outputTb4b4b4)
Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ff[ERROR]Ta5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertTrueTb4b4b4(Te6edf3resultsTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffconfig_invalidTa5d6ff"Tb4b4b4, Tff7b72FalseTb4b4b4)Tb4b4b4)

Tff7b72def Td2a8fftest_reticulum_diagnosis_empty_logfileTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Empty log file should be handled gracefully."""
Te6edf3rns_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8fftest_dirTb4b4b4, Ta5d6ff"Ta5d6ffrns_empty_logTa5d6ff"Tb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3rns_dirTb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rns_dirTb4b4b4, Ta5d6ff"Ta5d6ffconfigTa5d6ff"Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Ta5d6ff"Ta5d6ff[reticulum]Tffea00\nTa5d6ff"Tb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rns_dirTb4b4b4, Ta5d6ff"Ta5d6fflogfileTa5d6ff"Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Tff7b72pass

Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffupdate_pathsTb4b4b4(Te6edf3reticulum_config_dirTff7b72=Te6edf3rns_dirTb4b4b4)
Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffrun_reticulum_diagnosisTb4b4b4(Te6edf3fileTff7b72=Te6edf3outputTb4b4b4)
Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffLog file is emptyTa5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)

T8b949e# ==================================================================
T8b949e# Diagnosis edge cases
T8b949e# ==================================================================

Tff7b72def Td2a8fftest_diagnosis_empty_db_fileTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""0-byte database file should trigger a warning."""
Tffa657openTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdb_pathTb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4)Tff7b72.Td2a8ffcloseTb4b4b4(Tb4b4b4)

Te6edf3output Tff7b72= Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffrun_diagnosisTb4b4b4(Te6edf3fileTff7b72=Te6edf3outputTb4b4b4)
Te6edf3report Tff7b72= Te6edf3outputTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffempty (0 bytes)Ta5d6ff"Tb4b4b4, Te6edf3reportTb4b4b4)

Tff7b72def Td2a8fftest_update_pathsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""update_paths should correctly update internal state."""
Te6edf3new_storage Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8fftest_dirTb4b4b4, Ta5d6ff"Ta5d6ffnew_storageTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffupdate_pathsTb4b4b4(Te6edf3storage_dirTff7b72=Te6edf3new_storageTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffstorage_dirTb4b4b4, Te6edf3new_storageTb4b4b4)

Tff7b72def Td2a8fftest_keyboard_interrupt_passthroughTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""KeyboardInterrupt should be passed to the default hook."""
Te6edf3called Tff7b72= Tb4b4b4{Tb4b4b4}

Tff7b72def Td2a8ffmock_hookTb4b4b4(Te6edf3exc_typeTb4b4b4, Te6edf3exc_valueTb4b4b4, Te6edf3exc_tbTb4b4b4)Tb4b4b4:
Te6edf3calledTb4b4b4[Ta5d6ff"Ta5d6ffinvokedTa5d6ff"Tb4b4b4] Tff7b72= Tff7b72True

Te6edf3original Tff7b72= Te6edf3sysTff7b72.Td2a8ff__excepthook__
Te6edf3sysTff7b72.Td2a8ff__excepthook__ Tff7b72= Te6edf3mock_hook
Tff7b72tryTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffrecoveryTff7b72.Td2a8ffhandle_exceptionTb4b4b4(Tf85149KeyboardInterruptTb4b4b4, Tf85149KeyboardInterruptTb4b4b4(Tb4b4b4)Tb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertTrueTb4b4b4(Te6edf3calledTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffinvokedTa5d6ff"Tb4b4b4, Tff7b72FalseTb4b4b4)Tb4b4b4)
Tff7b72finallyTb4b4b4:
Te6edf3sysTff7b72.Td2a8ff__excepthook__ Tff7b72= Te6edf3original


Tff7b72if Tff7b72__name__ Tff7b72== Ta5d6ff"Ta5d6ff__main__Ta5d6ff"Tb4b4b4:
Te6edf3unittestTff7b72.Td2a8ffmainTb4b4b4(Tb4b4b4)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────